<template>
  <div class="container-page-audio">
    <openModule :has-history="hasHistory" @click="openBtnClickHandler" v-if="!isEditing" />
    <div class="item-loading" v-else-if="loading">加载中...</div>
    <el-form label-position="top" size="mini" v-else>
      <el-form-item>
        <el-button @click="uploadBefore(),uploadPlayBtnShow=false" v-if="uploadPlayBtnShow">继续上传</el-button>
        <div class="container-item-upload">
          <draggable :list="archiveForm.resources" :options="draggableOptions" @update="resourceSort">
            <div :class="[{'ignore-elements':!resource.rid}]" :key="index" v-for="(resource,index) in computedResource">
              <audioResourceItem :index="index" :resource="resource" />
            </div>
          </draggable>
          <div class="item-upload-btn upload-image-border el-icon-plus">
            <input @change="checkAndFilterFiles" accept=".mp3, .wav, .ogg" class="item-upload-input" multiple type="file" />
          </div>
        </div>
      </el-form-item>
      <el-form-item label="合辑封面">
        <coverModule :loading="coverLoading" :cover="archiveForm.cover" @change="setArchiveCover" />
      </el-form-item>
      <el-form-item label="合辑分类">
        <el-select placeholder="请选择" v-model="archiveForm.cid">
          <el-option :key="index" :label="classify.name" :value="classify.cid" v-for="(classify,index) in classifyList" />
        </el-select>
      </el-form-item>
      <el-form-item label="合辑标题">
        <el-input placeholder="请输入 (建议30字以内)" v-model="archiveForm.title" />
      </el-form-item>
      <el-form-item label="合辑简介 (选填)">
        <el-input :show-word-limit="true" placeholder="有趣的描述更容易被小编推荐为热门动态哦～(=ﾟωﾟ)ﾉ" resize="none" rows="6" type="textarea" v-model="archiveForm.mark" />
      </el-form-item>
      <el-form-item>
        <el-button :disabled="nowUploading" @click="submit" type="success" plain>保存草稿</el-button>
        <el-button :disabled="nowUploading" @click="submitExamine" type="primary" plain>提交审核</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
// api
import {
    getArchiveEditedAPI,
    createArchiveAPI,
    getArchiveDetailAPI,
    putArchiveAPI,
    submitExamineAPI,
} from "@/api/archive";
import { getClassifyAPI } from "@/api/term";
import { sortAudioResourceAPI, serverSimpleUploaderAPI } from "@/api/utils";
import generateOSS from "@/utils/uploadHandler";
import setting from "@/settings";
import draggable from "vuedraggable";
import { mapGetters } from "vuex";
import {
    analysisAudio, computedSign, formatFiles, verifyAudioFileMime,
} from "./utils/index";

import audioResourceItem from "./components/audioResourceItem.vue";
import openModule from "./components/open.vue";
import coverModule from "./components/cover.vue";

export default {
    components: {
        openModule,
        coverModule,
        audioResourceItem,
        draggable,
    },
    data() {
        return {
            archiveType: 2, // 2即为音频类型id
            hasHistory: null, // 修改后为true或false
            historyArchiveID: 0, // 如果是历史未提交稿件, 把它的id暂存到这里
            // isEditing: false, // 是否正在编辑
            isEditing: false, // 是否正在编辑
            loading: true, // 是否正在获取数据
            canSubmit: true, // 是否可提交, 目前用做提交按钮的禁用状态控制
            nowUploading: false, // 上传状态
            coverLoading: false, // 封面上传状态
            archiveForm: {}, // 稿件表单数据
            resourcesList: [], // 上传列表, 数组中的值即为待上传资源
            draggableOptions: {
                animation: 150, // 拖动排序的动画效果时间
                filter: ".ignore-elements", // 不导致拖拽的选择器(字符串或函数)
                forceFallback: false, // 忽略HTML5的DnD行为，并强制退出。（h5里有个属性也是拖动，这里是为了去掉H5拖动对这个的影响）
            },
            uploadPlayBtnShow: false,
            classifyList: [],
        };
    },
    computed: {
        uid() {
            return this.userInfo.uid;
        },
        aid() {
            return this.archiveForm.aid;
        },
        newResourceSort() {
            return this.archiveForm.resources.length + this.resourcesList.length;
        },
        ...mapGetters(["userInfo"]),
        computedResource() { // 显示列表
            const mixin = [...this.archiveForm.resources, ...this.resourcesList];
            return mixin;
        },
        editArchiveID() {
            return this.$route.params.aid;
            // return 20;
        },
    },
    created() {
        if (this.editArchiveID) {
            this.editOrCreateHandler();
        } else {
            this.checkHistory();
        }
    },
    methods: {
        async editOrCreateHandler() {
            this.isEditing = true;
            this.loading = true;
            this.archiveForm = await this.getArchiveDetail(this.editArchiveID);
            this.loading = false;
        },
        async checkHistory() {
            const { data } = await getArchiveEditedAPI(this.archiveType);
            this.hasHistory = data.length > 0;
            // 如果有历史未提交稿件就暂存历史稿件id
            if (this.hasHistory) this.historyArchiveID = data[0].aid;
        },
        async openBtnClickHandler() {
            this.loading = true;
            const aid = this.hasHistory ? this.historyArchiveID : await this.createNewArchive(this.archiveType);
            this.archiveForm = await this.getArchiveDetail(aid);
            this.loading = false;
            this.isEditing = true;
        },
        async createNewArchive(type) {
            const { data: aid } = await createArchiveAPI(type);
            return aid;
        },
        /** @获取文章稿件分类 */
        async getClassify() {
            const classifyResult = await getClassifyAPI(this.archiveType);
            this.classifyList = classifyResult.data;
        },
        async getArchiveDetail(aid) {
            await this.getClassify(); // 1,获取分类信息
            const { data: archive } = await getArchiveDetailAPI(aid); // 2,获取稿件详情
            archive.resources.forEach((resource) => { resource.selfHide = false; });
            return archive;
        },
        async submit() {
            await putArchiveAPI(this.aid, this.archiveForm);
            this.$message({ type: "success", message: "稿件信息保存成功" });
        },
        async submitExamine() {
            if (this.archiveForm.resources.length < 1) {
                this.$message.error("至少上传一个资源 (｀・ω・´) ");
                return;
            }
            // 这里要做个全屏的加载中,
            await putArchiveAPI(this.archiveForm.aid, this.archiveForm);
            await submitExamineAPI(this.archiveForm.aid);
            // 这里还要做个页面的跳转, 跳去自己的稿件管理列表
            this.$router.replace({ name: "audiosList" });
        },
        async setArchiveCover(file) {
            this.coverLoading = true;
            const { file_path: cover } = await serverSimpleUploaderAPI(file, "/audioArchiveCover");
            await putArchiveAPI(this.aid, { cover });
            this.archiveForm.cover = cover;
            this.coverLoading = false;
        },
        async checkAndFilterFiles(evt) {
            const { files } = evt.target;
            Object.values(files).forEach((file) => {
                if (verifyAudioFileMime(file)) { // 过滤文件格式并整理文件数据
                    const fileData = formatFiles(file);
                    this.resourcesList.push(fileData);
                }
            }, this);
            evt.target.value = null;
            if (this.resourcesList.length === 0) return; // 如果文件被过滤完了 那就直接中断
            if (this.nowUploading) return; // 这里做个上传中的判断, 正在上传中的话就不要另起新任务了
            this.uploadBefore();
        },
        async uploadBefore() {
            this.nowUploading = true; // 开启正在上传中状态
            const [uploadTask] = this.resourcesList;// 从上传列表中出栈一个上传任务
            if (!uploadTask.selfHide) {
                uploadTask.tip = 1;// 这里给上传任务的提示改为解析数据中状态
                await this.uploadHandler(uploadTask);
                uploadTask.tip = 3;
                this.archiveForm.resources.push(uploadTask); // 上传数据转入稿件资源列表内, 保持显示效果与获取详情一致
            }
            this.resourcesList.shift();// 从上传列表中出栈一个上传任务
            if (this.resourcesList.length === 0) {
                this.nowUploading = false; // 关闭正在上传中状态
                return;
            }
            this.uploadBefore(); // 如果还有任务就递归进行上传
        },
        async uploadHandler(uploadTask) {
            const { name, file } = uploadTask;
            const sign = computedSign(file); // 获得签名
            const { duration } = await analysisAudio(file); // 解析音频数据, 获取音频时长
            const client = await generateOSS(); // 获取oss实例
            uploadTask.client = client; // 把oss实例赋给上传任务, 这个在资源显示道具用做删除上传任务
            uploadTask.tip = 2; // 这个才是上传中
            try {
                const { data: { data } } = await client.multipartUpload(`audioResour/${sign}`, file, { // 进行实际的上传操作
                    progress: (val) => {
                        uploadTask.progress = Math.floor(val * 10000) / 100;
                    },
                    callback: await this.generateOSSCallback(duration, name),
                });
                uploadTask.rid = data.rid;
            } catch (error) {
                if (error.name === "cancel") {
                    this.$message.error("上传已取消");
                    this.uploadPlayBtnShow = this.resourcesList.length > 0;
                }
                this.nowUploading = false;
                console.error(error);
            } finally {
                delete uploadTask.client; // 无论结果怎么样, 操作完都把他的实例给删了
            }
        },

        async generateOSSCallback(duration, name) {
            const host = setting.baseURL.KujoMiva;
            const baseUrl = "/oss/callback/audio";
            const callbackUrl = [
                `https://server.miva.work/${baseUrl}`,
                // `http:${host}${baseUrl}`,
                // `http:${host}${baseUrl}`, // 最后几条应该设置失败通知回调, 最好在不同的服务器地址上设置回调, 最好有权限把失败的文件删除掉
            ].join(";");
            /* eslint no-template-curly-in-string: "off" */
            const ossParams = "size=${size}&path=${object}";
            const callbackOptions = {
                url: callbackUrl,
                body: `uid=${this.uid}&aid=${this.aid}&duration=${duration}&sort=${this.newResourceSort}&name=${name}&${ossParams}`,
            };
            return callbackOptions;
        },
        async resourceSort() {
            /** @type {Array} sortList 排序列表 */
            const sortList = this.archiveForm.resources;
            const sortRule = sortList.reduce((pv, val, index) => {
                pv.push({ rid: val.rid, sort: index });
                return pv;
            }, []);
            try {
                await sortAudioResourceAPI(sortRule);
            } catch (error) {
                console.error(error);
                this.$message.error("排序出错");
            }
        },
    }, // methods-end
};
</script>

<style lang="scss" src="./styles/index.scss"/>
